Setup

Load Libraries

library(tidyverse)
── Attaching core tidyverse packages ─────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.0     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.0
✔ ggplot2   3.4.1     ✔ tibble    3.2.1
✔ lubridate 1.9.2     ✔ tidyr     1.3.0
✔ purrr     1.0.1     ── Conflicts ───────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(here)
here() starts at /Users/stuartstenhouse/Codeclan/visit_scotland_codeclan_project
library(sf)
Linking to GEOS 3.11.0, GDAL 3.5.3, PROJ 9.1.0; sf_use_s2() is TRUE
library(infer)
library(ggridges)
library(modelr)
library(skimr)
library(ggfortify)

Run Cleaning Script, Read In Clean Data & Set Colour Scheme for Visualisations

source(here("scripts/cleaning_script.R"))

regional_domestic_tourism_individual <- read_csv(here("data/clean_data/regional_domestic_tourism_individual_clean.csv"))
regional_domestic_tourism_non_gb_clean <- read_csv(here("data/clean_data/regional_domestic_tourism_non_gb_clean.csv"))
international_visits <- read_csv(here("data/clean_data/international_visits_clean.csv"))
tourism_businesses <- read_csv(here("data/clean_data/tourism_businesses_clean.csv"))
dom_int_summary <- read_csv(here("data/clean_data/dom_int_summary_clean.csv"))

local_authority_geo <- st_read(dsn = "data/geo_data/", layer = "pub_las")

colour_scheme <- c("#540453", "#1d1d65", "#970061", "#b6cb2b", "#9fd6f3")

Annual Average Stats

Domestic

5 Figure Summary

dom_int_summary %>%
  filter(dom_int == "Domestic") %>% 
  skim()
── Data Summary ────────────────────────
                           Values    
Name                       Piped data
Number of rows             11        
Number of columns          4         
_______________________              
Column type frequency:               
  character                1         
  numeric                  3         
________________________             
Group variables            None      
dom_int_summary %>%
  filter(dom_int == "International") %>% 
  skim()
── Data Summary ────────────────────────
                           Values    
Name                       Piped data
Number of rows             11        
Number of columns          4         
_______________________              
Column type frequency:               
  character                1         
  numeric                  3         
________________________             
Group variables            None      

IQR

dom_int_summary %>%
  filter(dom_int == "Domestic") %>%  
  summarise(visits_iqr= IQR(visits),
            expenditure_iqr= IQR(spend))
dom_int_summary %>%
  filter(dom_int == "International") %>%  
  summarise(visits_iqr= IQR(visits),
            expenditure_iqr= IQR(spend))

Median

dom_int_summary %>%
  filter(dom_int == "Domestic") %>%  
  summarise(median_visits = median(visits),
            median_spend = median(spend))
NA
dom_int_summary %>%
  filter(dom_int == "International") %>%  
  summarise(median_visits = median(visits),
            median_spend = median(spend))

Domestic Tourism

Average Visits By Region

regional_data_joined %>% 
  group_by(local_authority) %>% 
  summarise(mean_visits = mean(visits)) %>% 
  arrange(desc(mean_visits))
Simple feature collection with 32 features and 2 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5512.998 ymin: 530250.8 xmax: 470332 ymax: 1220302
Projected CRS: OSGB36 / British National Grid

regional_data_joined %>% 
  group_by(code) %>% 
  summarise(mean_visits = mean(visits)) %>% 
  ggplot(aes(fill = mean_visits)) + 
  geom_sf(colour = "grey90", size = 0.1) +
  labs(
    x = "Longitude",
    y = "Latitude",
    title = "Average Annual Number of Domestic Vistors",
    subtitle = "By Region",
    fill = "Visits (Thousands)") +
  theme(panel.background = element_rect(fill = "white"),
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        rect = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank())

Expenditure by Region

regional_data_joined %>% 
  group_by(local_authority) %>% 
  summarise(mean_expenditure = mean(expenditure)) %>% 
  arrange(desc(mean_expenditure))
Simple feature collection with 32 features and 2 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5512.998 ymin: 530250.8 xmax: 470332 ymax: 1220302
Projected CRS: OSGB36 / British National Grid
regional_data_joined %>% 
  group_by(code) %>% 
  summarise(mean_exp = mean(expenditure)) %>% 
  ggplot(aes(fill = mean_exp)) + 
  geom_sf(colour = "grey90", size = 0.1) +
  labs(
    x = "Longitude",
    y = "Latitude",
    title = "Average Annual Expenditure of Domestic Vistors",
    subtitle = "By Region",
    fill = "Expenditure (Million GBP)") +
    theme(panel.background = element_rect(fill = "white"),
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        rect = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank())

Expenditure Per Visit

Mean Expenditure Per Visit Plot
regional_domestic_tourism_individual %>%
  filter(visits != 0,
         expenditure != 0) %>% 
  mutate(exp_per_visit = expenditure / visits, rm.na = TRUE) %>%
  group_by(local_authority) %>% 
  summarise(mean_exp_per_visit = mean(exp_per_visit)) %>% 
  arrange(desc(mean_exp_per_visit)) %>%
  ggplot() +
  geom_col(aes(x = reorder(local_authority, mean_exp_per_visit), y = mean_exp_per_visit,
               fill = local_authority %in% c("City of Edinburgh", "Glasgow City", "Highland")),
           show.legend = FALSE, colour = "white") +
  scale_fill_manual(values = c("FALSE" = "grey80",
                               "TRUE" = colour_scheme[1])) +
  coord_flip() +
  labs(
    x = "Region",
    y = "Mean Expenditure per Visit (Million GBP / Thousand Visits)",
    title = "Domestic Tourism Mean Expenditure per Visit") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "blank"))

Nights Stayed

Plot
regional_domestic_tourism_individual %>% 
  mutate(nights_per_visit = nights / visits) %>% 
  group_by(local_authority) %>% 
  summarise(mean_nights_per_visit = mean(nights_per_visit, na.rm = TRUE)) %>%
  ggplot() +
  geom_col(aes(x = reorder(local_authority, mean_nights_per_visit), y = mean_nights_per_visit,
               fill = local_authority %in% c("Shetland Islands", "Orkney Islands", "Na h-Eileanan Siar",
                                             "City of Edinburgh", "Glasgow City", "Highland")),
           show.legend = FALSE, colour = "white") +
  scale_fill_manual(values = c("FALSE" = "grey80",
                               "TRUE" = colour_scheme[1])) +
  coord_flip() +
  labs(
    x = "Region",
    y = "Avg. Nights per Visit",
    title = "Domestic Tourism Avg. Nights per Visit") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "blank"))

Map
regional_data_joined %>%
  mutate(nights_per_visit = nights / visits) %>% 
  group_by(local_authority) %>% 
  summarise(mean_nights_per_visit = mean(nights_per_visit, na.rm = TRUE)) %>%
  ggplot(aes(fill = mean_nights_per_visit)) + 
  geom_sf(colour = "grey90", size = 0.1) +
  labs(
    x = "Longitude",
    y = "Latitude",
    title = "Domestic Tourism Mean Nights per Visit",
    fill = "Mean Nights per Visit"
  ) +
  theme(panel.background = element_rect(fill = "white"),
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        rect = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        plot.title = element_text(size = 15, face = "bold"))

NA

Gross Value Added

tourism_businesses %>%
  filter(local_authority != "Scotland",
         year %in% c(2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019)) %>%
  group_by(local_authority) %>% 
  summarise(total_gva = sum(gva)) %>% 
  slice_max(total_gva, n = 5)
  
tourism_businesses %>%
  filter(local_authority %in% c("City of Edinburgh", "Glasgow City", "Aberdeen City",
                                "Highland", "Fife"),
         year %in% c(2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019)) %>%
  ggplot() +
  geom_boxplot(aes(x = gva, y = local_authority, fill = local_authority), 
               alpha = 0.8,
               show.legend = FALSE) +
  scale_fill_manual(values = colour_scheme) +
  scale_colour_manual(values = colour_scheme) +
  labs(
    x = "Gross Value Added (Million GBP)",
    y = "Local Authority",
    title = "Distribution of Annual Gross Value Added",
    subtitle = "Top 5 Regions: 2009-2019"
  ) +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", 
                                  linetype = "dashed"))

Scottish Based Tourism Compared To English Based Tourism

regional_data_joined_sco_eng %>% 
  filter(region_of_residence == "Scotland") %>%
  group_by(local_authority) %>%
  summarise(mean_visits = mean(visits)) %>% 
  ggplot(aes(fill = mean_visits)) + 
  geom_sf(colour = "grey90", size = 0.1) +
  labs(
    x = "Longitude",
    y = "Latitude",
    title = "Average Annual Number of Scottish Based Vistors",
    subtitle = "By Region",
    fill = "Visits (Thousands)") +
  theme(panel.background = element_rect(fill = "white"),
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        rect = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank())

regional_data_joined_sco_eng %>% 
  filter(region_of_residence == "England") %>% 
  group_by(local_authority) %>%
  summarise(mean_visits = mean(visits)) %>% 
  ggplot(aes(fill = mean_visits)) + 
  geom_sf(colour = "grey90", size = 0.5) +
  labs(
    x = "Longitude",
    y = "Latitude",
    title = "Average Annual Number of English Based Vistors",
    subtitle = "By Region",
    fill = "Visits (Thousands)") +
  theme(panel.background = element_rect(fill = "white"),
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        rect = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank())

Marketing Edinburgh to Domestic Tourists: Mini Case Study

Visits by Country of Residence
regional_domestic_tourism_non_gb_clean %>%
  filter(local_authority %in% c("City of Edinburgh")) %>% 
  ggplot(aes(x = visits, y = region_of_residence, fill = region_of_residence == "Scotland")) +
  geom_density_ridges(show.legend = FALSE, alpha = 0.5) +
  theme_ridges() +
  theme(axis.title.y = element_blank()) +
  scale_fill_manual(values = c("FALSE" = colour_scheme[2],
                               "TRUE" = colour_scheme[1])) +
  labs(
    title = "Distribution of Annual Visits by Country of Residence",
    subtitle = "Edinburgh",
    x = "Visits (Thousands)") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 13),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "dashed"),
        axis.text.y = element_text(face = "bold"))

Expenditure Per Visit by Country of Residence
regional_domestic_tourism_non_gb_clean %>%
  filter(local_authority %in% c("City of Edinburgh")) %>%
  mutate(exp_per_visit = expenditure / visits) %>% 
  ggplot(aes(x = exp_per_visit, y = region_of_residence, fill = region_of_residence == "Scotland")) +
  geom_density_ridges(show.legend = FALSE, alpha = 0.5) +
  theme_ridges() +
  theme(axis.title.y = element_blank()) +
  scale_fill_manual(values = c("FALSE" = colour_scheme[2],
                               "TRUE" = colour_scheme[1])) +
  labs(
    title = "Distribution of Expenditure per Visit by Country of Residence",
    subtitle = "Edinburgh",
    x = "Expenditure per Visit (Million GBP / Thousand Visits)") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 13),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "dashed"),
        axis.text.y = element_text(face = "bold"))

Nights by Country of Residence
regional_domestic_tourism_non_gb_clean %>%
  filter(local_authority %in% c("City of Edinburgh")) %>% 
  mutate(nights_per_visit = nights / visits) %>%
  ggplot(aes(x = nights_per_visit, y = region_of_residence, fill = region_of_residence == "Scotland")) +
  geom_density_ridges(show.legend = FALSE, alpha = 0.5) +
  theme_ridges() +
  theme(axis.title.y = element_blank()) +
  scale_fill_manual(values = c("FALSE" = colour_scheme[2],
                               "TRUE" = colour_scheme[1])) +
  labs(
    title = "Distribution of Nights by Country of Residence",
    subtitle = "Edinburgh",
    x = "Nights") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 13),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "dashed"),
        axis.text.y = element_text(face = "bold"))

Linear Model: Predict Expenditure by Visits
regional_domestic_tourism_non_gb_clean %>% 
  filter(local_authority == "City of Edinburgh",
         region_of_residence == "England") %>% 
  summarise(cor(expenditure, visits))
edinburgh_england <- regional_domestic_tourism_non_gb_clean %>% 
  filter(local_authority == "City of Edinburgh",
         region_of_residence == "England")
model_edinburgh <- lm(formula = expenditure ~ visits, data = edinburgh_england)
summary(model_edinburgh)

Call:
lm(formula = expenditure ~ visits, data = edinburgh_england)

Residuals:
    Min      1Q  Median      3Q     Max 
-24.193  -4.918   4.838   6.423  14.165 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) -493.61749   62.18315  -7.938 9.58e-05 ***
visits         0.62423    0.03945  15.824 9.76e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 12.34 on 7 degrees of freedom
Multiple R-squared:  0.9728,    Adjusted R-squared:  0.9689 
F-statistic: 250.4 on 1 and 7 DF,  p-value: 9.756e-07
autoplot(model_edinburgh)

  • Residuals vs. Fitted (Tests Independence of Residuals): No strong evidence of a pattern.
  • Normal Q-Q (Tests Normality of Residuals): Distribution of standardised residuals appears fairly normal.
  • Scale-Location (Tests Constancy of Variation of Residuals): No strong evidence of funneling.
edinburgh_england %>%
  add_predictions(model_edinburgh) %>%
  add_residuals(model_edinburgh) %>% 
  ggplot(aes(x = visits, y = expenditure)) +
  geom_point() +
  geom_line(aes(y = pred), col = colour_scheme[3], size = 1) +
  labs(
    x = "Visits (Thousands)",
    y = "Expenditure (Million GBP)",
    title = "English Based Visitors To Edinburgh: Expenditure / Visits",
    subtitle = "Based On 3 Year Annual Averages Between 2009-2019")

Model: spend ~ visits

Interpretation: ~97% of the variation in expenditure can be explained by the number of visits.

Question: The largest increase in visitor numbers is from 2009-2011 Avg. to 2010-2012 Avg. ~6%. If this percentage increase in visits was replicated in based on the most recent set of figures resulting in ~1803 (Thousand) visitors - what would the model predict for expenditure?

Answer: If visits were increased as above, the model would predict expenditure of ~632 Million GBP (Low Estimate ~620, High Estimate ~644)

As calculated below.

Step 1. outcome = b0 + b1 * 1st Predictor

Step 2. expenditure = b0(intercept) + b1(coefficient) * 1st Predictor

Step 3. expenditure = b0(intercept) + b1(coefficient) * visits

Step 4. expenditure = -493.61749 + 0.62423 * 1803

Step 5. expenditure = ~632 (Low Estimate ~620, High Estimate ~644)

632 + c(-12.34, 12.34)
[1] 619.66 644.34

International Tourism

Total Visitors by Country of Residence

international_visits %>% 
  select(-c(quarter, age, sample)) %>%
  filter(year %in% c(2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019),
         purpose == "Holiday") %>% 
  group_by(country) %>% 
  summarise(total_visits = sum(visits)) %>%
  slice_max(total_visits, n = 20) %>% 
  ggplot(aes(x = reorder(country, total_visits), y = total_visits)) +
  geom_col(aes(x = reorder(country, total_visits), y = total_visits,
               fill = country %in% c("USA")),
           show.legend = FALSE, colour = "white") +
  scale_fill_manual(values = c("FALSE" = "grey60",
                               "TRUE" = colour_scheme[1])) +
  coord_flip() +
  ylim(0, 3200) +
  labs(
    x = "Country",
    y = "Total Visits (Thousands)",
    title = "International Tourism: Total Visits (2002-2009)",
    subtitle = "Top 20 (Holiday Only)") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "blank"))

Total Expenditure by Country of Residence

international_visits %>% 
  select(-c(quarter, age, sample)) %>%
  filter(year %in% c(2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019),
         purpose == "Holiday") %>% 
  group_by(country) %>% 
  summarise(total_spend = sum(spend)) %>%
  slice_max(total_spend, n = 20) %>% 
  ggplot() +
  geom_col(aes(x = reorder(country, total_spend), y = total_spend,
               fill = country %in% c("USA")),
           show.legend = FALSE, colour = "white") +
  scale_fill_manual(values = c("FALSE" = "grey60",
                               "TRUE" = colour_scheme[1])) +
  coord_flip() +
  labs(
    x = "Country",
    y = "Total Expenditure (Million GBP)",
    title = "International Tourism: Total Expenditure (2002-2009)",
    subtitle = "Top 20 (Holiday Only)") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "blank"))

Expenditure per Visit by Country of Residence

Bar Plot

international_visits %>% 
  select(-c(quarter, age, sample)) %>%
  filter(year %in% c(2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019),
         purpose == "Holiday") %>% 
  group_by(country) %>% 
  summarise(total_spend = sum(spend),
            total_visits = sum(visits),
            spend_per_visit = total_spend / total_visits) %>%
  filter(total_visits > 500) %>%
  ggplot() +
  geom_col(aes(x = reorder(country, spend_per_visit), y = spend_per_visit,
               fill = country %in% c("Australia", "China", "Canada")),
           show.legend = FALSE, colour = "white") +
  scale_fill_manual(values = c("FALSE" = "grey60",
                               "TRUE" = colour_scheme[1])) +
  coord_flip() +
  labs(
    x = "Country",
    y = "Total Expenditure (Million GBP) / Total Visits (Thousands)",
    title = "International Tourism: Total Expenditure per Visit (2002-2009)",
    subtitle = "Countries w/ Over 500 Thousand Total Visits (Holiday Only)") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "blank"))

Scatter Plot

international_visits %>% 
  select(-c(quarter, age, sample)) %>%
  filter(year %in% c(2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019),
         purpose == "Holiday") %>% 
  group_by(country) %>% 
  summarise(total_spend = sum(spend),
            total_visits = sum(visits),
            spend_per_visit = total_spend / total_visits) %>%
  filter(total_visits > 500) %>% 
  ggplot(aes(x = total_visits, y = spend_per_visit)) +
  geom_point(aes(colour = country %in% c("Australia", "China", "Canada")), 
             show.legend = FALSE,
             size = 4) +
  scale_colour_manual(values = c("FALSE" = "grey60",
                                 "TRUE" = colour_scheme[3])) +
  ggrepel::geom_text_repel(aes(x = total_visits, y = spend_per_visit, label = country)) +
  labs(
    x = "Visits (Thousands)",
    y = "Total Expenditure (Million GBP) / Total Visits (Thousands)",
    title = "International Tourism: Visits vs. Expenditure Per Visit (2002-2009)",
    subtitle = "Countries w/ Over 500 Thousand Total Visits (Holiday Only)") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "dashed"))

Marketing Scotland To Canadian Based Tourists

\(H_0\): \(\mu_{\textrm{spend per visit(Q1+Q4)}} - \mu_{\textrm{spend per visit(Q2+Q3)}} = 0\) \(H_a\): \(\mu_{\textrm{spend per visit(Q1+Q4)}} - \mu_{\textrm{spend per visit(Q2+Q3)}} != 0\)

international_visits %>%
  filter(country == "Canada",
         purpose == "Holiday") %>% 
  mutate(exp_per_visit = spend / visits,
         spring_summer = if_else(quarter %in% c("Quarter 2", "Quarter 3"), "Yes", "No")) %>%  
  group_by(spring_summer) %>% 
  summarise(mean_visits = mean(visits),
            mean_exp = mean(spend),
            mean_exp_per_visit = mean(exp_per_visit))
canada_sample <- international_visits %>%
  filter(country == "Canada",
         purpose == "Holiday") %>% 
  mutate(exp_per_visit = spend / visits,
         spring_summer = if_else(quarter %in% c("Quarter 2", "Quarter 3"), "Yes", "No"))
observed_stat <- canada_sample %>% 
  specify(exp_per_visit ~ spring_summer) %>%
  calculate(stat = "diff in means", order = c("Yes", "No"))

observed_stat
Response: exp_per_visit (numeric)
Explanatory: spring_summer (factor)
null_distribution <- canada_sample %>% 
  specify(response = exp_per_visit, explanatory = spring_summer) %>%
  hypothesize(null = "independence") %>%
  generate(reps = 1000, type = "permute") %>% 
  calculate(stat = "diff in means", order = c("Yes", "No"))
null_distribution %>%
  visualise() +
  shade_p_value(obs_stat = observed_stat, direction = "both")

null_distribution %>%
  get_p_value(obs_stat = observed_stat, direction = "both")
LS0tCnRpdGxlOiAiVmlzaXQgU2NvdGxhbmQgQW5hbHlzaXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIFNldHVwCgojIyMgTG9hZCBMaWJyYXJpZXMKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShoZXJlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGluZmVyKQpsaWJyYXJ5KGdncmlkZ2VzKQpsaWJyYXJ5KG1vZGVscikKbGlicmFyeShza2ltcikKbGlicmFyeShnZ2ZvcnRpZnkpCmBgYAoKIyMjIFJ1biBDbGVhbmluZyBTY3JpcHQsIFJlYWQgSW4gQ2xlYW4gRGF0YSAmIFNldCBDb2xvdXIgU2NoZW1lIGZvciBWaXN1YWxpc2F0aW9ucwoKYGBge3J9CnNvdXJjZShoZXJlKCJzY3JpcHRzL2NsZWFuaW5nX3NjcmlwdC5SIikpCgpyZWdpb25hbF9kb21lc3RpY190b3VyaXNtX2luZGl2aWR1YWwgPC0gcmVhZF9jc3YoaGVyZSgiZGF0YS9jbGVhbl9kYXRhL3JlZ2lvbmFsX2RvbWVzdGljX3RvdXJpc21faW5kaXZpZHVhbF9jbGVhbi5jc3YiKSkKcmVnaW9uYWxfZG9tZXN0aWNfdG91cmlzbV9ub25fZ2JfY2xlYW4gPC0gcmVhZF9jc3YoaGVyZSgiZGF0YS9jbGVhbl9kYXRhL3JlZ2lvbmFsX2RvbWVzdGljX3RvdXJpc21fbm9uX2diX2NsZWFuLmNzdiIpKQppbnRlcm5hdGlvbmFsX3Zpc2l0cyA8LSByZWFkX2NzdihoZXJlKCJkYXRhL2NsZWFuX2RhdGEvaW50ZXJuYXRpb25hbF92aXNpdHNfY2xlYW4uY3N2IikpCnRvdXJpc21fYnVzaW5lc3NlcyA8LSByZWFkX2NzdihoZXJlKCJkYXRhL2NsZWFuX2RhdGEvdG91cmlzbV9idXNpbmVzc2VzX2NsZWFuLmNzdiIpKQpkb21faW50X3N1bW1hcnkgPC0gcmVhZF9jc3YoaGVyZSgiZGF0YS9jbGVhbl9kYXRhL2RvbV9pbnRfc3VtbWFyeV9jbGVhbi5jc3YiKSkKCmxvY2FsX2F1dGhvcml0eV9nZW8gPC0gc3RfcmVhZChkc24gPSAiZGF0YS9nZW9fZGF0YS8iLCBsYXllciA9ICJwdWJfbGFzIikKCmNvbG91cl9zY2hlbWUgPC0gYygiIzU0MDQ1MyIsICIjMWQxZDY1IiwgIiM5NzAwNjEiLCAiI2I2Y2IyYiIsICIjOWZkNmYzIikKYGBgCgojIyBBbm51YWwgQXZlcmFnZSBTdGF0cwoKIyMjIERvbWVzdGljCgojIyMjIDUgRmlndXJlIFN1bW1hcnkKCmBgYHtyfQpkb21faW50X3N1bW1hcnkgJT4lCiAgZmlsdGVyKGRvbV9pbnQgPT0gIkRvbWVzdGljIikgJT4lIAogIHNraW0oKQpgYGAKCmBgYHtyfQpkb21faW50X3N1bW1hcnkgJT4lCiAgZmlsdGVyKGRvbV9pbnQgPT0gIkludGVybmF0aW9uYWwiKSAlPiUgCiAgc2tpbSgpCmBgYAoKIyMjIyBJUVIKCmBgYHtyfQpkb21faW50X3N1bW1hcnkgJT4lCiAgZmlsdGVyKGRvbV9pbnQgPT0gIkRvbWVzdGljIikgJT4lICAKICBzdW1tYXJpc2UodmlzaXRzX2lxcj0gSVFSKHZpc2l0cyksCiAgICAgICAgICAgIGV4cGVuZGl0dXJlX2lxcj0gSVFSKHNwZW5kKSkKYGBgCgpgYGB7cn0KZG9tX2ludF9zdW1tYXJ5ICU+JQogIGZpbHRlcihkb21faW50ID09ICJJbnRlcm5hdGlvbmFsIikgJT4lICAKICBzdW1tYXJpc2UodmlzaXRzX2lxcj0gSVFSKHZpc2l0cyksCiAgICAgICAgICAgIGV4cGVuZGl0dXJlX2lxcj0gSVFSKHNwZW5kKSkKYGBgCgojIyMjIE1lZGlhbgoKYGBge3J9CmRvbV9pbnRfc3VtbWFyeSAlPiUKICBmaWx0ZXIoZG9tX2ludCA9PSAiRG9tZXN0aWMiKSAlPiUgIAogIHN1bW1hcmlzZShtZWRpYW5fdmlzaXRzID0gbWVkaWFuKHZpc2l0cyksCiAgICAgICAgICAgIG1lZGlhbl9zcGVuZCA9IG1lZGlhbihzcGVuZCkpCgpgYGAKCmBgYHtyfQpkb21faW50X3N1bW1hcnkgJT4lCiAgZmlsdGVyKGRvbV9pbnQgPT0gIkludGVybmF0aW9uYWwiKSAlPiUgIAogIHN1bW1hcmlzZShtZWRpYW5fdmlzaXRzID0gbWVkaWFuKHZpc2l0cyksCiAgICAgICAgICAgIG1lZGlhbl9zcGVuZCA9IG1lZGlhbihzcGVuZCkpCmBgYAoKIyMgVHJlbmRzIE92ZXIgVGltZQoKIyMjIE92ZXIgVGltZSAvIFZpc2l0cwoKYGBge3J9Cgpkb21faW50X3N1bW1hcnkgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gdmlzaXRzLCBjb2xvdXIgPSBkb21faW50KSwKICAgICAgICAgIHNpemUgPSAyKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IHllYXIsIHkgPSB2aXNpdHMsIGNvbG91ciA9IGRvbV9pbnQpLCAKICAgICAgICAgICAgIHNpemUgPSA0KSArCiAgeWxpbSgwLCAxNTAwMCkgKwogIGxhYnMoeCA9ICJcbiBZZWFyIiwKICAgICAgIHkgPSAiVmlzaXRvcnMgKFRob3VzYW5kcykgXG4iLAogICAgICAgdGl0bGUgPSAiQW5udWFsIFZpc2l0cyIsCiAgICAgICBzdWJ0aXRsZSA9ICJEb21lc3RpYyAmIEludGVybmF0aW9uYWwgT3Zlcm5pZ2h0IFZpc3RvcnMiLAogICAgICAgY29sb3VyID0gIiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygyMDA5LCAyMDEwLCAyMDExLCAyMDEyLCAyMDEzLCAyMDE0LCAyMDE1LCAyMDE2LCAyMDE3LCAyMDE4LCAyMDE5KSkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiRG9tZXN0aWMiID0gIiM1NDA0NTMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSW50ZXJuYXRpb25hbCIgPSAiIzlmZDZmMyIpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwKICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5OTAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpKQoKYGBgCgojIyMgT3ZlciBUaW1lIC8gRXhwZW5kaXR1cmUKCmBgYHtyfQoKZG9tX2ludF9zdW1tYXJ5ICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IHNwZW5kLCBjb2xvdXIgPSBkb21faW50KSwKICAgICAgICAgIHNpemUgPSAyKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IHllYXIsIHkgPSBzcGVuZCwgY29sb3VyID0gZG9tX2ludCksIAogICAgICAgICAgICAgc2l6ZSA9IDQpICsKICB5bGltKDAsIDQwMDApICsKICBsYWJzKHggPSAiXG4gWWVhciIsCiAgICAgICB5ID0gIkV4cGVuZGl0dXJlIChNaWxsaW9uIEdCUCkgXG4iLAogICAgICAgdGl0bGUgPSAiQW5udWFsIEV4cGVuZGl0dXJlIiwKICAgICAgIHN1YnRpdGxlID0gIkRvbWVzdGljICYgSW50ZXJuYXRpb25hbCBPdmVybmlnaHQgVmlzdG9ycyIsCiAgICAgICBjb2xvdXIgPSAiIikgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKDIwMDksIDIwMTAsIDIwMTEsIDIwMTIsIDIwMTMsIDIwMTQsIDIwMTUsIDIwMTYsIDIwMTcsIDIwMTgsIDIwMTkpKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJEb21lc3RpYyIgPSAiIzU0MDQ1MyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJbnRlcm5hdGlvbmFsIiA9ICIjOWZkNmYzIikpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXk5MCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIikpCgpgYGAKCiMjIERvbWVzdGljIFRvdXJpc20KCiMjIyMgQXZlcmFnZSBWaXNpdHMgQnkgUmVnaW9uCgpgYGB7cn0KcmVnaW9uYWxfZGF0YV9qb2luZWQgJT4lIAogIGdyb3VwX2J5KGxvY2FsX2F1dGhvcml0eSkgJT4lIAogIHN1bW1hcmlzZShtZWFuX3Zpc2l0cyA9IG1lYW4odmlzaXRzKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhtZWFuX3Zpc2l0cykpCmBgYAoKYGBge3J9CgpyZWdpb25hbF9kYXRhX2pvaW5lZCAlPiUgCiAgZ3JvdXBfYnkoY29kZSkgJT4lIAogIHN1bW1hcmlzZShtZWFuX3Zpc2l0cyA9IG1lYW4odmlzaXRzKSkgJT4lIAogIGdncGxvdChhZXMoZmlsbCA9IG1lYW5fdmlzaXRzKSkgKyAKICBnZW9tX3NmKGNvbG91ciA9ICJncmV5OTAiLCBzaXplID0gMC4xKSArCiAgbGFicygKICAgIHggPSAiTG9uZ2l0dWRlIiwKICAgIHkgPSAiTGF0aXR1ZGUiLAogICAgdGl0bGUgPSAiQXZlcmFnZSBBbm51YWwgTnVtYmVyIG9mIERvbWVzdGljIFZpc3RvcnMiLAogICAgc3VidGl0bGUgPSAiQnkgUmVnaW9uIiwKICAgIGZpbGwgPSAiVmlzaXRzIChUaG91c2FuZHMpIikgKwogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcmVjdCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKQoKYGBgCgojIyMjIEV4cGVuZGl0dXJlIGJ5IFJlZ2lvbgoKYGBge3J9CnJlZ2lvbmFsX2RhdGFfam9pbmVkICU+JSAKICBncm91cF9ieShsb2NhbF9hdXRob3JpdHkpICU+JSAKICBzdW1tYXJpc2UobWVhbl9leHBlbmRpdHVyZSA9IG1lYW4oZXhwZW5kaXR1cmUpKSAlPiUgCiAgYXJyYW5nZShkZXNjKG1lYW5fZXhwZW5kaXR1cmUpKQpgYGAKCgpgYGB7cn0KcmVnaW9uYWxfZGF0YV9qb2luZWQgJT4lIAogIGdyb3VwX2J5KGNvZGUpICU+JSAKICBzdW1tYXJpc2UobWVhbl9leHAgPSBtZWFuKGV4cGVuZGl0dXJlKSkgJT4lIAogIGdncGxvdChhZXMoZmlsbCA9IG1lYW5fZXhwKSkgKyAKICBnZW9tX3NmKGNvbG91ciA9ICJncmV5OTAiLCBzaXplID0gMC4xKSArCiAgbGFicygKICAgIHggPSAiTG9uZ2l0dWRlIiwKICAgIHkgPSAiTGF0aXR1ZGUiLAogICAgdGl0bGUgPSAiQXZlcmFnZSBBbm51YWwgRXhwZW5kaXR1cmUgb2YgRG9tZXN0aWMgVmlzdG9ycyIsCiAgICBzdWJ0aXRsZSA9ICJCeSBSZWdpb24iLAogICAgZmlsbCA9ICJFeHBlbmRpdHVyZSAoTWlsbGlvbiBHQlApIikgKwogICAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICByZWN0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKIyMjIyBFeHBlbmRpdHVyZSBQZXIgVmlzaXQKCiMjIyMjIE1lYW4gRXhwZW5kaXR1cmUgUGVyIFZpc2l0IFBsb3QKCmBgYHtyfQpyZWdpb25hbF9kb21lc3RpY190b3VyaXNtX2luZGl2aWR1YWwgJT4lCiAgZmlsdGVyKHZpc2l0cyAhPSAwLAogICAgICAgICBleHBlbmRpdHVyZSAhPSAwKSAlPiUgCiAgbXV0YXRlKGV4cF9wZXJfdmlzaXQgPSBleHBlbmRpdHVyZSAvIHZpc2l0cywgcm0ubmEgPSBUUlVFKSAlPiUKICBncm91cF9ieShsb2NhbF9hdXRob3JpdHkpICU+JSAKICBzdW1tYXJpc2UobWVhbl9leHBfcGVyX3Zpc2l0ID0gbWVhbihleHBfcGVyX3Zpc2l0KSkgJT4lIAogIGFycmFuZ2UoZGVzYyhtZWFuX2V4cF9wZXJfdmlzaXQpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9jb2woYWVzKHggPSByZW9yZGVyKGxvY2FsX2F1dGhvcml0eSwgbWVhbl9leHBfcGVyX3Zpc2l0KSwgeSA9IG1lYW5fZXhwX3Blcl92aXNpdCwKICAgICAgICAgICAgICAgZmlsbCA9IGxvY2FsX2F1dGhvcml0eSAlaW4lIGMoIkNpdHkgb2YgRWRpbmJ1cmdoIiwgIkdsYXNnb3cgQ2l0eSIsICJIaWdobGFuZCIpKSwKICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLCBjb2xvdXIgPSAid2hpdGUiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiRkFMU0UiID0gImdyZXk4MCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVFJVRSIgPSBjb2xvdXJfc2NoZW1lWzFdKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicygKICAgIHggPSAiUmVnaW9uIiwKICAgIHkgPSAiTWVhbiBFeHBlbmRpdHVyZSBwZXIgVmlzaXQgKE1pbGxpb24gR0JQIC8gVGhvdXNhbmQgVmlzaXRzKSIsCiAgICB0aXRsZSA9ICJEb21lc3RpYyBUb3VyaXNtIE1lYW4gRXhwZW5kaXR1cmUgcGVyIFZpc2l0IikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksCiAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTkwIiwgbGluZXR5cGUgPSAiYmxhbmsiKSkKYGBgCgojIyMjIE5pZ2h0cyBTdGF5ZWQKCiMjIyMjIFBsb3QKCmBgYHtyfQpyZWdpb25hbF9kb21lc3RpY190b3VyaXNtX2luZGl2aWR1YWwgJT4lIAogIG11dGF0ZShuaWdodHNfcGVyX3Zpc2l0ID0gbmlnaHRzIC8gdmlzaXRzKSAlPiUgCiAgZ3JvdXBfYnkobG9jYWxfYXV0aG9yaXR5KSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fbmlnaHRzX3Blcl92aXNpdCA9IG1lYW4obmlnaHRzX3Blcl92aXNpdCwgbmEucm0gPSBUUlVFKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fY29sKGFlcyh4ID0gcmVvcmRlcihsb2NhbF9hdXRob3JpdHksIG1lYW5fbmlnaHRzX3Blcl92aXNpdCksIHkgPSBtZWFuX25pZ2h0c19wZXJfdmlzaXQsCiAgICAgICAgICAgICAgIGZpbGwgPSBsb2NhbF9hdXRob3JpdHkgJWluJSBjKCJTaGV0bGFuZCBJc2xhbmRzIiwgIk9ya25leSBJc2xhbmRzIiwgIk5hIGgtRWlsZWFuYW4gU2lhciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDaXR5IG9mIEVkaW5idXJnaCIsICJHbGFzZ293IENpdHkiLCAiSGlnaGxhbmQiKSksCiAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwgY29sb3VyID0gIndoaXRlIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkZBTFNFIiA9ICJncmV5ODAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRSVUUiID0gY29sb3VyX3NjaGVtZVsxXSkpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnMoCiAgICB4ID0gIlJlZ2lvbiIsCiAgICB5ID0gIkF2Zy4gTmlnaHRzIHBlciBWaXNpdCIsCiAgICB0aXRsZSA9ICJEb21lc3RpYyBUb3VyaXNtIEF2Zy4gTmlnaHRzIHBlciBWaXNpdCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXk5MCIsIGxpbmV0eXBlID0gImJsYW5rIikpCmBgYAoKIyMjIyMgTWFwCgpgYGB7cn0KcmVnaW9uYWxfZGF0YV9qb2luZWQgJT4lCiAgbXV0YXRlKG5pZ2h0c19wZXJfdmlzaXQgPSBuaWdodHMgLyB2aXNpdHMpICU+JSAKICBncm91cF9ieShsb2NhbF9hdXRob3JpdHkpICU+JSAKICBzdW1tYXJpc2UobWVhbl9uaWdodHNfcGVyX3Zpc2l0ID0gbWVhbihuaWdodHNfcGVyX3Zpc2l0LCBuYS5ybSA9IFRSVUUpKSAlPiUKICBnZ3Bsb3QoYWVzKGZpbGwgPSBtZWFuX25pZ2h0c19wZXJfdmlzaXQpKSArIAogIGdlb21fc2YoY29sb3VyID0gImdyZXk5MCIsIHNpemUgPSAwLjEpICsKICBsYWJzKAogICAgeCA9ICJMb25naXR1ZGUiLAogICAgeSA9ICJMYXRpdHVkZSIsCiAgICB0aXRsZSA9ICJEb21lc3RpYyBUb3VyaXNtIE1lYW4gTmlnaHRzIHBlciBWaXNpdCIsCiAgICBmaWxsID0gIk1lYW4gTmlnaHRzIHBlciBWaXNpdCIKICApICsKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHJlY3QgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIikpCiAgCmBgYAoKIyMjIyBHcm9zcyBWYWx1ZSBBZGRlZAoKYGBge3J9CnRvdXJpc21fYnVzaW5lc3NlcyAlPiUKICBmaWx0ZXIobG9jYWxfYXV0aG9yaXR5ICE9ICJTY290bGFuZCIsCiAgICAgICAgIHllYXIgJWluJSBjKDIwMDksIDIwMTAsIDIwMTEsIDIwMTIsIDIwMTMsIDIwMTQsIDIwMTUsIDIwMTYsIDIwMTcsIDIwMTgsIDIwMTkpKSAlPiUKICBncm91cF9ieShsb2NhbF9hdXRob3JpdHkpICU+JSAKICBzdW1tYXJpc2UodG90YWxfZ3ZhID0gc3VtKGd2YSkpICU+JSAKICBzbGljZV9tYXgodG90YWxfZ3ZhLCBuID0gNSkKICAKdG91cmlzbV9idXNpbmVzc2VzICU+JQogIGZpbHRlcihsb2NhbF9hdXRob3JpdHkgJWluJSBjKCJDaXR5IG9mIEVkaW5idXJnaCIsICJHbGFzZ293IENpdHkiLCAiQWJlcmRlZW4gQ2l0eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkhpZ2hsYW5kIiwgIkZpZmUiKSwKICAgICAgICAgeWVhciAlaW4lIGMoMjAwOSwgMjAxMCwgMjAxMSwgMjAxMiwgMjAxMywgMjAxNCwgMjAxNSwgMjAxNiwgMjAxNywgMjAxOCwgMjAxOSkpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2JveHBsb3QoYWVzKHggPSBndmEsIHkgPSBsb2NhbF9hdXRob3JpdHksIGZpbGwgPSBsb2NhbF9hdXRob3JpdHkpLCAKICAgICAgICAgICAgICAgYWxwaGEgPSAwLjgsCiAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvdXJfc2NoZW1lKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xvdXJfc2NoZW1lKSArCiAgbGFicygKICAgIHggPSAiR3Jvc3MgVmFsdWUgQWRkZWQgKE1pbGxpb24gR0JQKSIsCiAgICB5ID0gIkxvY2FsIEF1dGhvcml0eSIsCiAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQW5udWFsIEdyb3NzIFZhbHVlIEFkZGVkIiwKICAgIHN1YnRpdGxlID0gIlRvcCA1IFJlZ2lvbnM6IDIwMDktMjAxOSIKICApICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXk5MCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIikpCmBgYAoKIyMjIyBTY290dGlzaCBCYXNlZCBUb3VyaXNtIENvbXBhcmVkIFRvIEVuZ2xpc2ggQmFzZWQgVG91cmlzbQoKYGBge3J9CnJlZ2lvbmFsX2RhdGFfam9pbmVkX3Njb19lbmcgJT4lIAogIGZpbHRlcihyZWdpb25fb2ZfcmVzaWRlbmNlID09ICJTY290bGFuZCIpICU+JQogIGdyb3VwX2J5KGxvY2FsX2F1dGhvcml0eSkgJT4lCiAgc3VtbWFyaXNlKG1lYW5fdmlzaXRzID0gbWVhbih2aXNpdHMpKSAlPiUgCiAgZ2dwbG90KGFlcyhmaWxsID0gbWVhbl92aXNpdHMpKSArIAogIGdlb21fc2YoY29sb3VyID0gImdyZXk5MCIsIHNpemUgPSAwLjEpICsKICBsYWJzKAogICAgeCA9ICJMb25naXR1ZGUiLAogICAgeSA9ICJMYXRpdHVkZSIsCiAgICB0aXRsZSA9ICJBdmVyYWdlIEFubnVhbCBOdW1iZXIgb2YgU2NvdHRpc2ggQmFzZWQgVmlzdG9ycyIsCiAgICBzdWJ0aXRsZSA9ICJCeSBSZWdpb24iLAogICAgZmlsbCA9ICJWaXNpdHMgKFRob3VzYW5kcykiKSArCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICByZWN0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKYGBge3J9CnJlZ2lvbmFsX2RhdGFfam9pbmVkX3Njb19lbmcgJT4lIAogIGZpbHRlcihyZWdpb25fb2ZfcmVzaWRlbmNlID09ICJFbmdsYW5kIikgJT4lIAogIGdyb3VwX2J5KGxvY2FsX2F1dGhvcml0eSkgJT4lCiAgc3VtbWFyaXNlKG1lYW5fdmlzaXRzID0gbWVhbih2aXNpdHMpKSAlPiUgCiAgZ2dwbG90KGFlcyhmaWxsID0gbWVhbl92aXNpdHMpKSArIAogIGdlb21fc2YoY29sb3VyID0gImdyZXk5MCIsIHNpemUgPSAwLjUpICsKICBsYWJzKAogICAgeCA9ICJMb25naXR1ZGUiLAogICAgeSA9ICJMYXRpdHVkZSIsCiAgICB0aXRsZSA9ICJBdmVyYWdlIEFubnVhbCBOdW1iZXIgb2YgRW5nbGlzaCBCYXNlZCBWaXN0b3JzIiwKICAgIHN1YnRpdGxlID0gIkJ5IFJlZ2lvbiIsCiAgICBmaWxsID0gIlZpc2l0cyAoVGhvdXNhbmRzKSIpICsKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHJlY3QgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyMjIE1hcmtldGluZyBFZGluYnVyZ2ggdG8gRG9tZXN0aWMgVG91cmlzdHM6IE1pbmkgQ2FzZSBTdHVkeQoKIyMjIyMgVmlzaXRzIGJ5IENvdW50cnkgb2YgUmVzaWRlbmNlCgpgYGB7cn0KcmVnaW9uYWxfZG9tZXN0aWNfdG91cmlzbV9ub25fZ2JfY2xlYW4gJT4lCiAgZmlsdGVyKGxvY2FsX2F1dGhvcml0eSAlaW4lIGMoIkNpdHkgb2YgRWRpbmJ1cmdoIikpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB2aXNpdHMsIHkgPSByZWdpb25fb2ZfcmVzaWRlbmNlLCBmaWxsID0gcmVnaW9uX29mX3Jlc2lkZW5jZSA9PSAiU2NvdGxhbmQiKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMoc2hvdy5sZWdlbmQgPSBGQUxTRSwgYWxwaGEgPSAwLjUpICsKICB0aGVtZV9yaWRnZXMoKSArCiAgdGhlbWUoYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiRkFMU0UiID0gY29sb3VyX3NjaGVtZVsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUUlVFIiA9IGNvbG91cl9zY2hlbWVbMV0pKSArCiAgbGFicygKICAgIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBBbm51YWwgVmlzaXRzIGJ5IENvdW50cnkgb2YgUmVzaWRlbmNlIiwKICAgIHN1YnRpdGxlID0gIkVkaW5idXJnaCIsCiAgICB4ID0gIlZpc2l0cyAoVGhvdXNhbmRzKSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXk5MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKQpgYGAKCiMjIyMjIEV4cGVuZGl0dXJlIFBlciBWaXNpdCBieSBDb3VudHJ5IG9mIFJlc2lkZW5jZQoKYGBge3J9CnJlZ2lvbmFsX2RvbWVzdGljX3RvdXJpc21fbm9uX2diX2NsZWFuICU+JQogIGZpbHRlcihsb2NhbF9hdXRob3JpdHkgJWluJSBjKCJDaXR5IG9mIEVkaW5idXJnaCIpKSAlPiUKICBtdXRhdGUoZXhwX3Blcl92aXNpdCA9IGV4cGVuZGl0dXJlIC8gdmlzaXRzKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZXhwX3Blcl92aXNpdCwgeSA9IHJlZ2lvbl9vZl9yZXNpZGVuY2UsIGZpbGwgPSByZWdpb25fb2ZfcmVzaWRlbmNlID09ICJTY290bGFuZCIpKSArCiAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhzaG93LmxlZ2VuZCA9IEZBTFNFLCBhbHBoYSA9IDAuNSkgKwogIHRoZW1lX3JpZGdlcygpICsKICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJGQUxTRSIgPSBjb2xvdXJfc2NoZW1lWzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRSVUUiID0gY29sb3VyX3NjaGVtZVsxXSkpICsKICBsYWJzKAogICAgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEV4cGVuZGl0dXJlIHBlciBWaXNpdCBieSBDb3VudHJ5IG9mIFJlc2lkZW5jZSIsCiAgICBzdWJ0aXRsZSA9ICJFZGluYnVyZ2giLAogICAgeCA9ICJFeHBlbmRpdHVyZSBwZXIgVmlzaXQgKE1pbGxpb24gR0JQIC8gVGhvdXNhbmQgVmlzaXRzKSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXk5MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKQpgYGAKCiMjIyMjIE5pZ2h0cyBieSBDb3VudHJ5IG9mIFJlc2lkZW5jZQoKYGBge3J9CnJlZ2lvbmFsX2RvbWVzdGljX3RvdXJpc21fbm9uX2diX2NsZWFuICU+JQogIGZpbHRlcihsb2NhbF9hdXRob3JpdHkgJWluJSBjKCJDaXR5IG9mIEVkaW5idXJnaCIpKSAlPiUgCiAgbXV0YXRlKG5pZ2h0c19wZXJfdmlzaXQgPSBuaWdodHMgLyB2aXNpdHMpICU+JQogIGdncGxvdChhZXMoeCA9IG5pZ2h0c19wZXJfdmlzaXQsIHkgPSByZWdpb25fb2ZfcmVzaWRlbmNlLCBmaWxsID0gcmVnaW9uX29mX3Jlc2lkZW5jZSA9PSAiU2NvdGxhbmQiKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMoc2hvdy5sZWdlbmQgPSBGQUxTRSwgYWxwaGEgPSAwLjUpICsKICB0aGVtZV9yaWRnZXMoKSArCiAgdGhlbWUoYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiRkFMU0UiID0gY29sb3VyX3NjaGVtZVsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUUlVFIiA9IGNvbG91cl9zY2hlbWVbMV0pKSArCiAgbGFicygKICAgIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBOaWdodHMgYnkgQ291bnRyeSBvZiBSZXNpZGVuY2UiLAogICAgc3VidGl0bGUgPSAiRWRpbmJ1cmdoIiwKICAgIHggPSAiTmlnaHRzIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMyksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksCiAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTkwIiwgbGluZXR5cGUgPSAiZGFzaGVkIiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikpCmBgYAoKCiMjIyMjIExpbmVhciBNb2RlbDogUHJlZGljdCBFeHBlbmRpdHVyZSBieSBWaXNpdHMKCmBgYHtyfQpyZWdpb25hbF9kb21lc3RpY190b3VyaXNtX25vbl9nYl9jbGVhbiAlPiUgCiAgZmlsdGVyKGxvY2FsX2F1dGhvcml0eSA9PSAiQ2l0eSBvZiBFZGluYnVyZ2giLAogICAgICAgICByZWdpb25fb2ZfcmVzaWRlbmNlID09ICJFbmdsYW5kIikgJT4lIAogIHN1bW1hcmlzZShjb3IoZXhwZW5kaXR1cmUsIHZpc2l0cykpCmBgYAoKYGBge3J9CmVkaW5idXJnaF9lbmdsYW5kIDwtIHJlZ2lvbmFsX2RvbWVzdGljX3RvdXJpc21fbm9uX2diX2NsZWFuICU+JSAKICBmaWx0ZXIobG9jYWxfYXV0aG9yaXR5ID09ICJDaXR5IG9mIEVkaW5idXJnaCIsCiAgICAgICAgIHJlZ2lvbl9vZl9yZXNpZGVuY2UgPT0gIkVuZ2xhbmQiKQpgYGAKCmBgYHtyfQptb2RlbF9lZGluYnVyZ2ggPC0gbG0oZm9ybXVsYSA9IGV4cGVuZGl0dXJlIH4gdmlzaXRzLCBkYXRhID0gZWRpbmJ1cmdoX2VuZ2xhbmQpCnN1bW1hcnkobW9kZWxfZWRpbmJ1cmdoKQpgYGAKCmBgYHtyfQphdXRvcGxvdChtb2RlbF9lZGluYnVyZ2gpCmBgYAoKLSBSZXNpZHVhbHMgdnMuIEZpdHRlZCAoVGVzdHMgSW5kZXBlbmRlbmNlIG9mIFJlc2lkdWFscyk6IE5vIHN0cm9uZyBldmlkZW5jZSBvZiBhIHBhdHRlcm4uIAotIE5vcm1hbCBRLVEgKFRlc3RzIE5vcm1hbGl0eSBvZiBSZXNpZHVhbHMpOiBEaXN0cmlidXRpb24gb2Ygc3RhbmRhcmRpc2VkIHJlc2lkdWFscyBhcHBlYXJzIGZhaXJseSBub3JtYWwuIAotIFNjYWxlLUxvY2F0aW9uIChUZXN0cyBDb25zdGFuY3kgb2YgVmFyaWF0aW9uIG9mIFJlc2lkdWFscyk6IE5vIHN0cm9uZyBldmlkZW5jZSBvZiBmdW5uZWxpbmcuCgpgYGB7cn0KZWRpbmJ1cmdoX2VuZ2xhbmQgJT4lCiAgYWRkX3ByZWRpY3Rpb25zKG1vZGVsX2VkaW5idXJnaCkgJT4lCiAgYWRkX3Jlc2lkdWFscyhtb2RlbF9lZGluYnVyZ2gpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB2aXNpdHMsIHkgPSBleHBlbmRpdHVyZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fbGluZShhZXMoeSA9IHByZWQpLCBjb2wgPSBjb2xvdXJfc2NoZW1lWzNdLCBzaXplID0gMSkgKwogIGxhYnMoCiAgICB4ID0gIlZpc2l0cyAoVGhvdXNhbmRzKSIsCiAgICB5ID0gIkV4cGVuZGl0dXJlIChNaWxsaW9uIEdCUCkiLAogICAgdGl0bGUgPSAiRW5nbGlzaCBCYXNlZCBWaXNpdG9ycyBUbyBFZGluYnVyZ2g6IEV4cGVuZGl0dXJlIC8gVmlzaXRzIiwKICAgIHN1YnRpdGxlID0gIkJhc2VkIE9uIDMgWWVhciBBbm51YWwgQXZlcmFnZXMgQmV0d2VlbiAyMDA5LTIwMTkiKQpgYGAKTW9kZWw6IHNwZW5kIH4gdmlzaXRzCgpJbnRlcnByZXRhdGlvbjogfjk3JSBvZiB0aGUgdmFyaWF0aW9uIGluIGV4cGVuZGl0dXJlIGNhbiBiZSBleHBsYWluZWQgYnkgdGhlIG51bWJlciBvZiB2aXNpdHMuIAoKUXVlc3Rpb246IFRoZSBsYXJnZXN0IGluY3JlYXNlIGluIHZpc2l0b3IgbnVtYmVycyBpcyBmcm9tIDIwMDktMjAxMSBBdmcuIHRvIDIwMTAtMjAxMiBBdmcuIH42JS4gSWYgdGhpcyBwZXJjZW50YWdlIGluY3JlYXNlIGluIHZpc2l0cyB3YXMgcmVwbGljYXRlZCBpbiBiYXNlZCBvbiB0aGUgbW9zdCByZWNlbnQgc2V0IG9mIGZpZ3VyZXMgcmVzdWx0aW5nIGluIH4xODAzIChUaG91c2FuZCkgdmlzaXRvcnMgLSB3aGF0IHdvdWxkIHRoZSBtb2RlbCBwcmVkaWN0IGZvciBleHBlbmRpdHVyZT8KCkFuc3dlcjogSWYgdmlzaXRzIHdlcmUgaW5jcmVhc2VkIGFzIGFib3ZlLCB0aGUgbW9kZWwgd291bGQgcHJlZGljdCBleHBlbmRpdHVyZSBvZiB+NjMyIE1pbGxpb24gR0JQIChMb3cgRXN0aW1hdGUgfjYyMCwgSGlnaCBFc3RpbWF0ZSB+NjQ0KQoKQXMgY2FsY3VsYXRlZCBiZWxvdy4KClN0ZXAgMS4Kb3V0Y29tZSA9IGIwICsgYjEgKiAxc3QgUHJlZGljdG9yCgpTdGVwIDIuCmV4cGVuZGl0dXJlID0gYjAoaW50ZXJjZXB0KSArIGIxKGNvZWZmaWNpZW50KSAqIDFzdCBQcmVkaWN0b3IKClN0ZXAgMy4KZXhwZW5kaXR1cmUgPSBiMChpbnRlcmNlcHQpICsgYjEoY29lZmZpY2llbnQpICogYHZpc2l0c2AKClN0ZXAgNC4KZXhwZW5kaXR1cmUgPSAtNDkzLjYxNzQ5ICsgMC42MjQyMyAqIGAxODAzYAoKU3RlcCA1LgpleHBlbmRpdHVyZSA9IH42MzIgKExvdyBFc3RpbWF0ZSB+NjIwLCBIaWdoIEVzdGltYXRlIH42NDQpCgpgYGB7cn0KNjMyICsgYygtMTIuMzQsIDEyLjM0KQpgYGAKCiMjIEludGVybmF0aW9uYWwgVG91cmlzbQoKIyMjIFRvdGFsIFZpc2l0b3JzIGJ5IENvdW50cnkgb2YgUmVzaWRlbmNlCgpgYGB7cn0KaW50ZXJuYXRpb25hbF92aXNpdHMgJT4lIAogIHNlbGVjdCgtYyhxdWFydGVyLCBhZ2UsIHNhbXBsZSkpICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygyMDA5LCAyMDEwLCAyMDExLCAyMDEyLCAyMDEzLCAyMDE0LCAyMDE1LCAyMDE2LCAyMDE3LCAyMDE4LCAyMDE5KSwKICAgICAgICAgcHVycG9zZSA9PSAiSG9saWRheSIpICU+JSAKICBncm91cF9ieShjb3VudHJ5KSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsX3Zpc2l0cyA9IHN1bSh2aXNpdHMpKSAlPiUKICBzbGljZV9tYXgodG90YWxfdmlzaXRzLCBuID0gMjApICU+JSAKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGNvdW50cnksIHRvdGFsX3Zpc2l0cyksIHkgPSB0b3RhbF92aXNpdHMpKSArCiAgZ2VvbV9jb2woYWVzKHggPSByZW9yZGVyKGNvdW50cnksIHRvdGFsX3Zpc2l0cyksIHkgPSB0b3RhbF92aXNpdHMsCiAgICAgICAgICAgICAgIGZpbGwgPSBjb3VudHJ5ICVpbiUgYygiVVNBIikpLAogICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UsIGNvbG91ciA9ICJ3aGl0ZSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJGQUxTRSIgPSAiZ3JleTYwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUUlVFIiA9IGNvbG91cl9zY2hlbWVbMV0pKSArCiAgY29vcmRfZmxpcCgpICsKICB5bGltKDAsIDMyMDApICsKICBsYWJzKAogICAgeCA9ICJDb3VudHJ5IiwKICAgIHkgPSAiVG90YWwgVmlzaXRzIChUaG91c2FuZHMpIiwKICAgIHRpdGxlID0gIkludGVybmF0aW9uYWwgVG91cmlzbTogVG90YWwgVmlzaXRzICgyMDAyLTIwMDkpIiwKICAgIHN1YnRpdGxlID0gIlRvcCAyMCAoSG9saWRheSBPbmx5KSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXk5MCIsIGxpbmV0eXBlID0gImJsYW5rIikpCmBgYAoKIyMjIFRvdGFsIEV4cGVuZGl0dXJlIGJ5IENvdW50cnkgb2YgUmVzaWRlbmNlCgpgYGB7cn0KaW50ZXJuYXRpb25hbF92aXNpdHMgJT4lIAogIHNlbGVjdCgtYyhxdWFydGVyLCBhZ2UsIHNhbXBsZSkpICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygyMDA5LCAyMDEwLCAyMDExLCAyMDEyLCAyMDEzLCAyMDE0LCAyMDE1LCAyMDE2LCAyMDE3LCAyMDE4LCAyMDE5KSwKICAgICAgICAgcHVycG9zZSA9PSAiSG9saWRheSIpICU+JSAKICBncm91cF9ieShjb3VudHJ5KSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsX3NwZW5kID0gc3VtKHNwZW5kKSkgJT4lCiAgc2xpY2VfbWF4KHRvdGFsX3NwZW5kLCBuID0gMjApICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9jb2woYWVzKHggPSByZW9yZGVyKGNvdW50cnksIHRvdGFsX3NwZW5kKSwgeSA9IHRvdGFsX3NwZW5kLAogICAgICAgICAgICAgICBmaWxsID0gY291bnRyeSAlaW4lIGMoIlVTQSIpKSwKICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLCBjb2xvdXIgPSAid2hpdGUiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiRkFMU0UiID0gImdyZXk2MCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVFJVRSIgPSBjb2xvdXJfc2NoZW1lWzFdKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicygKICAgIHggPSAiQ291bnRyeSIsCiAgICB5ID0gIlRvdGFsIEV4cGVuZGl0dXJlIChNaWxsaW9uIEdCUCkiLAogICAgdGl0bGUgPSAiSW50ZXJuYXRpb25hbCBUb3VyaXNtOiBUb3RhbCBFeHBlbmRpdHVyZSAoMjAwMi0yMDA5KSIsCiAgICBzdWJ0aXRsZSA9ICJUb3AgMjAgKEhvbGlkYXkgT25seSkiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwKICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5OTAiLCBsaW5ldHlwZSA9ICJibGFuayIpKQpgYGAKCiMjIyBFeHBlbmRpdHVyZSBwZXIgVmlzaXQgYnkgQ291bnRyeSBvZiBSZXNpZGVuY2UKCiMjIyMgQmFyIFBsb3QKCmBgYHtyfQppbnRlcm5hdGlvbmFsX3Zpc2l0cyAlPiUgCiAgc2VsZWN0KC1jKHF1YXJ0ZXIsIGFnZSwgc2FtcGxlKSkgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDIwMDksIDIwMTAsIDIwMTEsIDIwMTIsIDIwMTMsIDIwMTQsIDIwMTUsIDIwMTYsIDIwMTcsIDIwMTgsIDIwMTkpLAogICAgICAgICBwdXJwb3NlID09ICJIb2xpZGF5IikgJT4lIAogIGdyb3VwX2J5KGNvdW50cnkpICU+JSAKICBzdW1tYXJpc2UodG90YWxfc3BlbmQgPSBzdW0oc3BlbmQpLAogICAgICAgICAgICB0b3RhbF92aXNpdHMgPSBzdW0odmlzaXRzKSwKICAgICAgICAgICAgc3BlbmRfcGVyX3Zpc2l0ID0gdG90YWxfc3BlbmQgLyB0b3RhbF92aXNpdHMpICU+JQogIGZpbHRlcih0b3RhbF92aXNpdHMgPiA1MDApICU+JQogIGdncGxvdCgpICsKICBnZW9tX2NvbChhZXMoeCA9IHJlb3JkZXIoY291bnRyeSwgc3BlbmRfcGVyX3Zpc2l0KSwgeSA9IHNwZW5kX3Blcl92aXNpdCwKICAgICAgICAgICAgICAgZmlsbCA9IGNvdW50cnkgJWluJSBjKCJBdXN0cmFsaWEiLCAiQ2hpbmEiLCAiQ2FuYWRhIikpLAogICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UsIGNvbG91ciA9ICJ3aGl0ZSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJGQUxTRSIgPSAiZ3JleTYwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUUlVFIiA9IGNvbG91cl9zY2hlbWVbMV0pKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKAogICAgeCA9ICJDb3VudHJ5IiwKICAgIHkgPSAiVG90YWwgRXhwZW5kaXR1cmUgKE1pbGxpb24gR0JQKSAvIFRvdGFsIFZpc2l0cyAoVGhvdXNhbmRzKSIsCiAgICB0aXRsZSA9ICJJbnRlcm5hdGlvbmFsIFRvdXJpc206IFRvdGFsIEV4cGVuZGl0dXJlIHBlciBWaXNpdCAoMjAwMi0yMDA5KSIsCiAgICBzdWJ0aXRsZSA9ICJDb3VudHJpZXMgdy8gT3ZlciA1MDAgVGhvdXNhbmQgVG90YWwgVmlzaXRzIChIb2xpZGF5IE9ubHkpIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksCiAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTkwIiwgbGluZXR5cGUgPSAiYmxhbmsiKSkKYGBgCgojIyMjIFNjYXR0ZXIgUGxvdAoKYGBge3J9CmludGVybmF0aW9uYWxfdmlzaXRzICU+JSAKICBzZWxlY3QoLWMocXVhcnRlciwgYWdlLCBzYW1wbGUpKSAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMjAwOSwgMjAxMCwgMjAxMSwgMjAxMiwgMjAxMywgMjAxNCwgMjAxNSwgMjAxNiwgMjAxNywgMjAxOCwgMjAxOSksCiAgICAgICAgIHB1cnBvc2UgPT0gIkhvbGlkYXkiKSAlPiUgCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lIAogIHN1bW1hcmlzZSh0b3RhbF9zcGVuZCA9IHN1bShzcGVuZCksCiAgICAgICAgICAgIHRvdGFsX3Zpc2l0cyA9IHN1bSh2aXNpdHMpLAogICAgICAgICAgICBzcGVuZF9wZXJfdmlzaXQgPSB0b3RhbF9zcGVuZCAvIHRvdGFsX3Zpc2l0cykgJT4lCiAgZmlsdGVyKHRvdGFsX3Zpc2l0cyA+IDUwMCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHRvdGFsX3Zpc2l0cywgeSA9IHNwZW5kX3Blcl92aXNpdCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBjb3VudHJ5ICVpbiUgYygiQXVzdHJhbGlhIiwgIkNoaW5hIiwgIkNhbmFkYSIpKSwgCiAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgICAgc2l6ZSA9IDQpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIkZBTFNFIiA9ICJncmV5NjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVFJVRSIgPSBjb2xvdXJfc2NoZW1lWzNdKSkgKwogIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChhZXMoeCA9IHRvdGFsX3Zpc2l0cywgeSA9IHNwZW5kX3Blcl92aXNpdCwgbGFiZWwgPSBjb3VudHJ5KSkgKwogIGxhYnMoCiAgICB4ID0gIlZpc2l0cyAoVGhvdXNhbmRzKSIsCiAgICB5ID0gIlRvdGFsIEV4cGVuZGl0dXJlIChNaWxsaW9uIEdCUCkgLyBUb3RhbCBWaXNpdHMgKFRob3VzYW5kcykiLAogICAgdGl0bGUgPSAiSW50ZXJuYXRpb25hbCBUb3VyaXNtOiBWaXNpdHMgdnMuIEV4cGVuZGl0dXJlIFBlciBWaXNpdCAoMjAwMi0yMDA5KSIsCiAgICBzdWJ0aXRsZSA9ICJDb3VudHJpZXMgdy8gT3ZlciA1MDAgVGhvdXNhbmQgVG90YWwgVmlzaXRzIChIb2xpZGF5IE9ubHkpIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksCiAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTkwIiwgbGluZXR5cGUgPSAiZGFzaGVkIikpCmBgYAoKIyMjIE1hcmtldGluZyBTY290bGFuZCBUbyBDYW5hZGlhbiBCYXNlZCBUb3VyaXN0cwoKJEhfMCQ6ICRcbXVfe1x0ZXh0cm17c3BlbmQgcGVyIHZpc2l0KFExK1E0KX19IC0gXG11X3tcdGV4dHJte3NwZW5kIHBlciB2aXNpdChRMitRMyl9fSA9IDAkCiRIX2EkOiAkXG11X3tcdGV4dHJte3NwZW5kIHBlciB2aXNpdChRMStRNCl9fSAtIFxtdV97XHRleHRybXtzcGVuZCBwZXIgdmlzaXQoUTIrUTMpfX0gIT0gMCQKCmBgYHtyfQppbnRlcm5hdGlvbmFsX3Zpc2l0cyAlPiUKICBmaWx0ZXIoY291bnRyeSA9PSAiQ2FuYWRhIiwKICAgICAgICAgcHVycG9zZSA9PSAiSG9saWRheSIpICU+JSAKICBtdXRhdGUoZXhwX3Blcl92aXNpdCA9IHNwZW5kIC8gdmlzaXRzLAogICAgICAgICBzcHJpbmdfc3VtbWVyID0gaWZfZWxzZShxdWFydGVyICVpbiUgYygiUXVhcnRlciAyIiwgIlF1YXJ0ZXIgMyIpLCAiWWVzIiwgIk5vIikpICU+JSAgCiAgZ3JvdXBfYnkoc3ByaW5nX3N1bW1lcikgJT4lIAogIHN1bW1hcmlzZShtZWFuX3Zpc2l0cyA9IG1lYW4odmlzaXRzKSwKICAgICAgICAgICAgbWVhbl9leHAgPSBtZWFuKHNwZW5kKSwKICAgICAgICAgICAgbWVhbl9leHBfcGVyX3Zpc2l0ID0gbWVhbihleHBfcGVyX3Zpc2l0KSkKYGBgCmBgYHtyfQpjYW5hZGFfc2FtcGxlIDwtIGludGVybmF0aW9uYWxfdmlzaXRzICU+JQogIGZpbHRlcihjb3VudHJ5ID09ICJDYW5hZGEiLAogICAgICAgICBwdXJwb3NlID09ICJIb2xpZGF5IikgJT4lIAogIG11dGF0ZShleHBfcGVyX3Zpc2l0ID0gc3BlbmQgLyB2aXNpdHMsCiAgICAgICAgIHNwcmluZ19zdW1tZXIgPSBpZl9lbHNlKHF1YXJ0ZXIgJWluJSBjKCJRdWFydGVyIDIiLCAiUXVhcnRlciAzIiksICJZZXMiLCAiTm8iKSkKYGBgCgpgYGB7cn0Kb2JzZXJ2ZWRfc3RhdCA8LSBjYW5hZGFfc2FtcGxlICU+JSAKICBzcGVjaWZ5KGV4cF9wZXJfdmlzaXQgfiBzcHJpbmdfc3VtbWVyKSAlPiUKICBjYWxjdWxhdGUoc3RhdCA9ICJkaWZmIGluIG1lYW5zIiwgb3JkZXIgPSBjKCJZZXMiLCAiTm8iKSkKCm9ic2VydmVkX3N0YXQKYGBgCgpgYGB7cn0KbnVsbF9kaXN0cmlidXRpb24gPC0gY2FuYWRhX3NhbXBsZSAlPiUgCiAgc3BlY2lmeShyZXNwb25zZSA9IGV4cF9wZXJfdmlzaXQsIGV4cGxhbmF0b3J5ID0gc3ByaW5nX3N1bW1lcikgJT4lCiAgaHlwb3RoZXNpemUobnVsbCA9ICJpbmRlcGVuZGVuY2UiKSAlPiUKICBnZW5lcmF0ZShyZXBzID0gMTAwMCwgdHlwZSA9ICJwZXJtdXRlIikgJT4lIAogIGNhbGN1bGF0ZShzdGF0ID0gImRpZmYgaW4gbWVhbnMiLCBvcmRlciA9IGMoIlllcyIsICJObyIpKQpgYGAKCmBgYHtyfQpudWxsX2Rpc3RyaWJ1dGlvbiAlPiUKICB2aXN1YWxpc2UoKSArCiAgc2hhZGVfcF92YWx1ZShvYnNfc3RhdCA9IG9ic2VydmVkX3N0YXQsIGRpcmVjdGlvbiA9ICJib3RoIikKYGBgCgpgYGB7cn0KbnVsbF9kaXN0cmlidXRpb24gJT4lCiAgZ2V0X3BfdmFsdWUob2JzX3N0YXQgPSBvYnNlcnZlZF9zdGF0LCBkaXJlY3Rpb24gPSAiYm90aCIpCmBgYAoK